/*************************************************************************
	> File Name: dataitem.cpp
	> Author: xuwenlong
	> Mail: myxuan475@126.com 
	> Created Time: 2018年02月24日 星期六 16时00分30秒
 ************************************************************************/
#include "dataitem.h"
#include <stdio.h>
#include <utils/custom.h>
#include <acquisition/acquisition.h>
#include "tempbuf.h"
#include <transport/transport_manager.h>
#include "chnmanager.h"

DataItem::DataItem(const ID_DEV &devId, const S32 modelId):
    m_iDevAddr(devId),
    m_modelId(modelId),
    m_iOperator(this) {
}

DataItem::DataItem():
    m_modelId(-1),
    m_iOperator(this) {
}

DataItem::DataItem(const DataItem &item):
    m_iOperator(this)
{
    *this = item;
    m_iOperator.SetInterface(this);
}

DataItem::~DataItem()
{
    m_listValues.clear();
    m_listExprs.clear();
}

BOOL DataItem::IsEmpty()
{
    if (m_strname.empty() ||
            m_listExprs.empty() ||
            m_listValues.empty() ||
            !m_tDataExpr.valid())
        return TRUE;
    return FALSE;
}

string &DataItem::GetName()
{
    return m_strname;
}

string &DataItem::GetDot()
{
    return m_strdot;
}

S32 DataItem::GetItemId() const
{
    return m_iItemId;
}

void DataItem::SetAddr(ID_DEV &devId)
{
    m_iDevAddr = devId;
}

void DataItem::SetTempleId(S32 modelId)
{
    m_modelId = modelId;
}

void DataItem::SetName(const string &name)
{
    m_strname = name;
}

void DataItem::SetDot(const string &dot)
{
    m_strdot = dot;
}

void DataItem::SetItemId(S32 itemId)
{
    m_iItemId = itemId;
}

void DataItem::SetRegLength(S32 reglen)
{
    m_reglen = reglen;
}

void DataItem::ParseParams(const vector<string> &params)
{
    m_listExprs.clear();
    m_listValues.clear();
    m_iOperator.clearOut();
    for(int i = 0;i<params.size();i++) {
#if 0
        vector<string> list =
                utils::Split(params[i]," ");
        string paralist;
        string paras;
        for (int j = 0;j<list.size();j++) {
            paras += list.at(j);
            if (j != list.size()-1)
                paras += " ";
        }

        if (list.size() > 1)
            paralist +="["+paras+"]";
        else
            paralist += paras;
#endif
        tExpress expr = wrapExpress(params[i]);
        if (!expr.valid())
            return;

//        Operator iOperator(this);
//        iOperator.PushStack(Operator::AUTO_PARAM);
        m_listValues.push_back(expr->GenCmd(m_iOperator));
        m_listExprs.push_back(expr);
    }
}

vector<OpValue> DataItem::ParseString(const string &str)
{
    vector<OpValue> listValues;
    Operator iOp(NULL);
    vector<string> params = utils::Split(str,";");
    for(int i = 0;i<params.size();i++) {
        vector<string> list =
                utils::Split(params[i],",");
        string paralist;
        string paras;
        for (int j = 0;j<list.size();j++) {
            paras += list.at(j);
            if (j != list.size()-1)
                paras += " ";
        }

        if (list.size() > 1)
            paralist +="["+paras+"]";
        else
            paralist += paras;

        tExpress expr = wrapExpress(paralist);
        if (!expr.valid())
            return listValues;
        listValues.push_back(expr->GenCmd(iOp));
    }
    return listValues;
}

void DataItem::CalcParams(const vector<OpValue> &params)
{
    m_iOperator.clearOut();
    m_listValues.clear();

    ParamsLock palock(m_iOperator);
    m_iOperator.AddtoStack(Operator::AUTO_PARAM,params);
    for (vector<tExpress>::iterator iter = m_listExprs.begin();iter !=
         m_listExprs.end();iter++) {
        tExpress expr = *iter;
        if (!expr.valid()) {
            LOG_ERR("params expr is null");
            m_listValues.push_back(OpValue::Null());
            continue;
        }
        m_listValues.push_back(expr->GenCmd(m_iOperator));
    }
}

void DataItem::ParseDataExpr(const string &expr, F32 rate)
{
    m_fRate = rate;
    m_tDataExpr = wrapExpress(expr);
}

tExpress DataItem::LocateFunction(const string &def, int funcId)
{
    tTemplate temp = ChnManager::instance()->GetTemplate(m_modelId);
    if (temp.valid())
        return temp->LocateFunction(def.c_str(),funcId);
    return NULL;
}

const ID_DEV &DataItem::DevAddr()
{
    return m_iDevAddr;
}

OpValue DataItem::GenerateNext()
{
    m_iFuncId++;

    tExpress expr = getExpr(0,m_iFuncId);
    if (!expr.valid()) {
        return OpValue::Null();
    }
    return expr->GenCmd(m_iOperator);
}

OpValue DataItem::GenerateCmd()
{
    //恢复计算
    m_iFuncId = 0;
    m_iOperator.clearOut();

    ParamsLock palock(m_iOperator);
    m_iOperator.AddtoStack(Operator::AUTO_PARAM,m_listValues);
    tExpress expr = getExpr(0,m_iFuncId);
    if (!expr.valid()) {
        LOG_ERR("express is invalid");
        return CmdValue::Null();

    }
    return expr->GenCmd(m_iOperator);
}

RECV_RESULT DataItem::ParseRecvCmd(
        const CmdValue &recvCmd,
        S32 funcId)
{
    if (funcId != -1)
        m_iFuncId = funcId;
    if (recvCmd.IsEmpty())
        return RECV_NOT_AVAILIABLE;

    ParamsLock palock(m_iOperator);
    m_iOperator.AddtoStack(Operator::AUTO_PARAM,m_listValues);
    tExpress expr = getExpr(1,m_iFuncId);

    if (!expr.valid()) {
        LOG_ERR("express is invalid");
        return RECV_NOT_AVAILIABLE;
    }

//#ifndef LOCAL_TEST
        OpValue result = expr->ParseCmd(m_iOperator,0,recvCmd);
//#else
//        OpValue result = 1;
//#endif

    if (result.IsEmpty())
        return RECV_NOT_AVAILIABLE;
    //校验
    OpValue chk = m_iOperator["chk"];
    if (chk.IsEmpty())
        return RECV_COMPLETE;
    if (chk.Integer() == 0)
        return RECV_NOT_AVAILIABLE;
    return RECV_COMPLETE;
}

OpValue DataItem::Result()
{
    tExpress expr = m_tDataExpr;
    if (!expr.valid())
        return OpValue::Null();
//#ifdef LOCAL_TEST
//        return 0;
//#endif
    S32 acq = m_iItemId/10000;
    if ( acq == 3 || acq == 1 || acq == 4) {

        OpValue result = expr->ParseCmd(m_iOperator);
        return RateCall(result,m_fRate);
    }
    else
        return expr->ParseCmd(m_iOperator);
}

void DataItem::ResetCmd()
{
    m_iFuncId = 0;
    m_iOperator.clearOut();
}

string DataItem::FuncName(int flag)
{
    if (m_iItemId/10000 == 3 || m_iItemId/10000 == 1||
            m_iItemId/10000 == 4) {
        return flag == 0?"send":"recv";
    }
    else if (m_iItemId/10000 == 2) {
        return flag == 0?"indict":"undict";
    }
    else {
        return flag == 0?"modsnd":"modrcv";
    }
}

bool DataItem::isCmdEqual(const tDataItem &item)
{
    S32 it1;
    S32 it2;

    if (!item.valid())
        return false;
    it1 = item->m_iItemId/10000;
    it2 = m_iItemId/10000;
    if (it1 != 2 && it2 != 2) {
        return isParamEqual(item);
    }
    return false;
}

bool DataItem::isParamEqual(const tDataItem &item)
{
    vector<OpValue>::iterator it1 = m_listValues.begin();
    vector<OpValue>::iterator it2 = item->m_listValues.begin();

    while (it1 != m_listValues.end() && it2 != item->m_listValues.end()) {
        if (*it1 != *it2) {
            return false;
        }
        it1++;
        it2++;
    }

    if (it1 != m_listValues.end() || it2 != item->m_listValues.end())
        return false;
    return true;
}

tExpress DataItem::getExpr(
        int flag,
        int funcId)
{
    return LocateFunction(FuncName(flag),funcId);
}

TYPE_DEFINE DataItem::DataType()
{
    if (!floatcmp(m_fRate,1))
        return TYPE_F32;
    if (!m_tDataExpr.valid())
        return TYPE_CMD;
    return m_tDataExpr->ResultType();
}

OpValue DataItem::FuncCall()
{
    ParamsLock palock(m_iOperator);
    m_iOperator.AddtoStack(Operator::AUTO_PARAM,m_listValues);

    tExpress expr = m_tDataExpr;
    if (!expr.valid())
        return OpValue::Null();
    OpValue result = expr->ParseCmd(m_iOperator);
    if (result.IsEmpty())
        return result;
    return RateCall(result,m_fRate);
}

OpValue DataItem::RateCall(OpValue &result,float rate)
{
    float f = rate;
    switch(result.type) {
    case TYPE_S8:
    case TYPE_U8:
    case TYPE_S16:
    case TYPE_U16:
    case TYPE_S32:
    case TYPE_U32:
    case TYPE_S64:
    case TYPE_U64:
    {
        if (floatcmp(f,1))
            return result;
        else
            return result/f;
    }
    case TYPE_F32:
    case TYPE_F64:
        return result/f;
    default:
        return result/f;
    }
}

tExpress DataItem::wrapExpress(const string &str)
{
    TempBuf tempBuf(str);
    S32 pos = 0;
    TempBuf::RESULT res = tempBuf.Parse(pos,true);
    if ((res != TempBuf::OK && res != TempBuf::FIN))
        return NULL;
    return tempBuf.ResultExpress();
}

const S32 DataItem::RegLength()
{
    return m_reglen;
}
